import { toJS, remove, when, makeAutoObservable, keys, reaction, has, set } from 'mobx'

const test=false
// 单个zone跟踪结构, 一个zone多个objects
export function createMonitorZone(zoneId, rule) {
  const monitorZone = makeAutoObservable({
    zoneId,
    rule,
    objects: {},
    // 简单的违规计算, 只要衍生状态就可以
    get isZoneCountLeastViolated() {
      return monitorZone.rule["name"] === "in_area_count_least" && 
        keys(monitorZone.objects).length < monitorZone.rule["countLeast"]
    },
    get isZoneCountMaxViolated() {
      return monitorZone.rule["name"] === "in_area_count_max" 
        && keys(monitorZone.objects).length > monitorZone.rule["countMax"]
    },
    addObject(obj) {
      if (has(monitorZone.objects, obj.dev_id)) return
      set(monitorZone.objects, obj.dev_id, obj)
    },
    rmObject(obj) {
      if (!has(monitorZone.objects, obj.dev_id)) return
      remove(monitorZone.objects, obj.dev_id)
    }
  })
  // 衍生状态的反应需要用when
  when(
    () =>  monitorZone.isZoneCountLeastViolated,
    () => {
      console.log(alert_text("", true, monitorZone.rule.name, monitorZone.zoneId))
      test && console.log(toJS(monitorZone.objects))
    }
  )
  reaction(
    ()=>monitorZone.isZoneCountLeastViolated,
    violate=> {
      console.log(alert_text("", violate, monitorZone.rule.name, monitorZone.zoneId))
      test && console.log(toJS(monitorZone.objects))
    }
  )
  reaction(
    ()=> monitorZone.isZoneCountMaxViolated,
    violate=> {
      console.log(alert_text("", violate, monitorZone.rule.name, monitorZone.zoneId))
      test && console.log(toJS(monitorZone.objects))
    }
  )
  return monitorZone
}

// zone跟踪集合
export const monitorZoneStore = makeAutoObservable({
  zones: {},
  initZone(zoneId, rule) {
    if (!has(monitorZoneStore.zones, zoneId)) {
      set(monitorZoneStore.zones, zoneId, createMonitorZone(zoneId, rule))
    }
  },
  // 增加zone和zone的object
  addZoneRule(zoneId, obj) {
    monitorZoneStore.zones[zoneId].addObject(obj)
  },
  removeZoneRule(zoneId, obj) {
    if (has(monitorZoneStore.zones, zoneId)) {
      monitorZoneStore.zones[zoneId].rmObject(obj)
    }
  }
})

// 单个tko跟踪结构
export function createMonitorTko(rule, obj) {
  const monitorTko = makeAutoObservable({
    rule,
    obj,
    tmHandler: null,
    pauseTmHandler: null,
    // 复杂的违规状态计算, 需要单独用一个状态旗标
    violateFlag: false,
    _violate() {
      monitorTko.violateFlag = true
    },
    setViolate(bool) {
      if (bool===true) {
        monitorTko.tmHandler = setTimeout(
          ()=> { 
            monitorTko._violate()
            clearTimeout(monitorTko.tmHandler)
          }
        , monitorTko.rule.timeout)
      } else {
        monitorTko.violateFlag = false
        clearTimeout(monitorTko.tmHandler)
      }
    },
    updateTkoPos(obj) {
      if (monitorTko.obj.x===obj.x && monitorTko.obj.y===obj.y) {
        monitorTko.pauseTmHandler = setTimeout(
          (x, y) => {
            if (x===monitorTko.obj.x && y===monitorTko.obj.y) {
              monitorTko._violate()
              clearTimeout(monitorTko.pauseTmHandler)
            }
          }
        , monitorTko.rule.timeout, obj.x, obj.y)
      } else {
        monitorTko.violateFlag = false
        clearTimeout(monitorTko.pauseTmHandler)
      }
      monitorTko.obj = obj
    }
  })
  // 因为状态旗标不是衍生性的, 所以不能用when. 
  reaction (
    ()=> monitorTko.violateFlag,
    violate=> {
      console.log("tko ", 
      alert_text(monitorTko.obj.dev_id, violate, monitorTko.rule.name, monitorTko.rule.zoneId))
    }
  )
  return monitorTko
}

// 多个tko跟踪结构集合
// mobx react 不知道变动是add or remove 引起的
// 需要手动设置. 但是mst通过patch能够实现    
// op: "replace" | "add" | "remove"
export const monitorTkoStore = makeAutoObservable({
  tkos: {},
  addTkoRule(rule, obj) {
    let tkoKey = `${rule.zoneId}_${obj.dev_id}`
    if (!has(monitorTkoStore.tkos, tkoKey)) {
      set(monitorTkoStore.tkos, tkoKey, createMonitorTko(rule, obj))
      if (rule.name==="keep_out") {
        monitorTkoStore.tkos[tkoKey].setViolate(true)
      }
    } else {
      if (rule.name==="keep_in")   {
        monitorTkoStore.tkos[tkoKey].setViolate(false)
      } 
    }
  },
  removeTkoRule(rule, obj) {
    let tkoKey = `${rule.zoneId}_${obj.dev_id}`
    if (has(monitorTkoStore.tkos, tkoKey)) {
      if (rule.name==="keep_in") {
        monitorTkoStore.tkos[tkoKey].setViolate(true)
      } 
      if (rule.name==="keep_out") {
        monitorTkoStore.tkos[tkoKey].setViolate(false)
        remove(monitorTko.tkos, tkoKey)
      }
      if (rule.name==="in_area_pause_limit") {
        // 保证暂停规则的timout被clear
        clearTimeout(monitorTkoStore.tkos[tkoKey].pauseTmHandler)
        remove(monitorTkoStore.tkos, tkoKey)
      }
    }
  },
  updateTkoRule(rule, obj) {
    let tkoKey = `${rule.zoneId}_${obj.dev_id}`
    if (!has(monitorTkoStore.tkos, tkoKey)) {
      set(monitorTkoStore.tkos, tkoKey, createMonitorTko(rule, obj))
    } else {
      monitorTkoStore.tkos[tkoKey].updateTkoPos(obj)
    }
  }
})

const alert_text = (tkoid, violate_state, rule, zone, objects) => `${tkoid} ${violate_state? 'violated' : 'cleared'} rule ${rule} in zone ${zone}`
